#include<Arduino.h>
#include<ESP8266WiFi.h>
#include<ESP8266HTTPClient.h>
#include"ganix/all.hpp"

const bool SERVER_MODE = true;

static String SSID = "GA_Proj_3780C458";
static String PASSWD = "22453BB3";
static int BAUD = 115200;

void test_logger() {
    ganix::singleton::logger().info(String("") + "hello," + millis());
}

void run_lumen() {
    ganix::singleton::logger().put_param("lumen", String(ganix::singleton::bh1750().recv_lumen()));
}

// esp8266 的GPIO2、GPIO0、TX均要求启动时拉高，不适合作为开关输入，故使用RX作为输入
const u_int8_t GPIO2 = 2, GPIO0 = 0, RX = 3;

String server_addr = "";
String path[2];
ESP8266WebServer *server;

void http_sw_on_handler() {
    Serial.printf("requesting: %s \n", server->uri().c_str());
    server->send(200, "text/plain", "ok");
    digitalWrite(GPIO0, HIGH);
    digitalWrite(GPIO2, LOW);
}

void http_sw_off_handler() {
    Serial.printf("requesting: %s \n", server->uri().c_str());
    server->send(200, "text/plain", "ok");
    digitalWrite(GPIO0, LOW);
    digitalWrite(GPIO2, HIGH);
}

void inject_http_handler() {
    server = ganix::http_server::get_server();
    server->on("/on", http_sw_on_handler);
    server->on("/off", http_sw_off_handler);
}

int flush_sw(bool force = false) {
    static int sw = HIGH;
    u_int8_t flag = digitalRead(RX);
    //digitalWrite(GPIO2, flag);
    int ret_code = 0;
    if (sw != flag || force) {
        String response;
        Serial.printf("path:%s\n", path[flag].c_str(), path[flag]);
        ret_code = ganix::http::get(path[flag], response, 5000);
        if (ret_code == HTTP_CODE_OK) {
            if (response == "ok"){
                sw = flag;
            }
        }
    }
    return ret_code;
}

void setup_as_recver() {
    pinMode(GPIO0, OUTPUT);
    digitalWrite(GPIO0, LOW);
    inject_http_handler();
}

void setup_as_sender() {
    server_addr = "http://" + WiFi.gatewayIP().toString() + "/";
    path[HIGH] = server_addr + "on";
    path[LOW] = server_addr + "off";
    pinMode(RX, INPUT);
    int twinkle = HIGH;
    while (flush_sw(true) != HTTP_CODE_OK) {
        Serial.printf("init failed, delay 1500ms and retry\n");
        digitalWrite(GPIO2, twinkle);
        delay(1500);
        twinkle = !twinkle;
    }
    Serial.println("init finish.");
}

void setup() {
    pinMode(GPIO2, OUTPUT);
    digitalWrite(GPIO2, LOW);
    ganix::config::set_baud(BAUD);
    if (SERVER_MODE) {
        ganix::config::enable_wifi(SSID, PASSWD, true);
        ganix::config::enable_http_server();
    } else {
        ganix::config::enable_wifi(SSID, PASSWD, false);
    }
    ganix::config::start_init();

    if (SERVER_MODE) {
        setup_as_recver();
    } else {
        setup_as_sender();
    }
    digitalWrite(GPIO2, HIGH);
}

int last_force = 0;

void change_light() {
    static int flag = 0;
    flag = 1 - flag;
    digitalWrite(GPIO2, flag);
    Serial.printf("light : %d\n", flag);
}

void loop() {
    if (SERVER_MODE) {
        ganix::http_server::loop();
    } else {
        int current = millis();
        if (current > last_force + 5000) {
            flush_sw(true);
            last_force = current;
            change_light();
        } else {
            if (flush_sw() == HTTP_CODE_OK) {
                last_force = current;
                change_light();
            }
        }
    }
}
